package sk.naive.talker.command;

import sk.naive.talker.message.DefaultMessageFactory;
import sk.naive.talker.util.Utils;
import sk.naive.talker.persistence.PersistenceException;
import sk.naive.talker.props.PropertyStoreException;

import java.rmi.RemoteException;
import java.util.*;

/**
 *
 * @author <a href="mailto:virgo@naive.deepblue.sk">Richard "Virgo" Richter</a>
 * @version $Revision: 1.29 $ $Date: 2005/01/19 22:41:26 $
 */
public abstract class AbstractSetCommand extends AbstractCommand {
	public void exec()
		throws CommandException, RemoteException, PropertyStoreException
	{
		permissionCheck();
		if (params == null || params.length() == 0) {
			user.send(showSettings());
		} else {
			processParameters();
		}
	}

	protected void processParameters() throws RemoteException, CommandException, PropertyStoreException {
		String[] words = Utils.split(params, "\\s*=\\s*", 2);
		String key = Utils.mapKeyUnqote(words[0]);
		key = stripQuotes(key);
		if (settable() != null) {
			key = Utils.findFirstInCollection(words[0], settable(), true);
			if (key == null) {
				ctxSet(DefaultMessageFactory.CTXKEY_VAL, words[0]);
				sendHelper().sendMessage(user, getPropertyNotFoundKey());
				return;
			}
		}
		ctxSet(DefaultMessageFactory.CTXKEY_VAL, key);
		if (words.length > 1) {
			try {
				Set<String> validValues = getValidValues(key);
				String value = stripQuotes(words[1]);
				if (validValues != null) {
					value = Utils.findFirstInCollection(value, validValues, true);
					if (value == null) {
						sendInvalidValueMessage(words[1]);
						return;
					}
				} else {
					if (value == null || value.length() == 0) {
						value = getDefault(key);
						if (value == null) {
							value = "";
						}
					}
				}
				value = setValue(key, value);
				if (value != null) {
					sendSetValueMessage(value);
				} else {
					sendSetVoidValueMessage();
				}
			} catch (PropertyStoreException e) {
				sendInvalidValueMessage(words[1]);
			} catch (PersistenceException e) {
				throw new CommandException(e);
			}
		} else {
			if (!setUpKeys().contains(key)) {
				sendHelper().sendMessage(user, getPropertyNotFoundKey());
				return;
			}
			String value = getValue(key);
			if (value == null) {
				value = "";
			}
			StringBuilder sb = new StringBuilder();
			if (getValidValues(key) != null) {
				ctxSet(DefaultMessageFactory.CTXKEY_VAL + "Value", Utils.formatCollection(getValidValues(key), ", "));
				sb.append(getString(getValidValuesKey(), user.getProperties()));
			}
			ctxSet(DefaultMessageFactory.CTXKEY_VAL + "Value", value);
			sb.append(getString(getCurrentValueKey(), user.getProperties()));
			user.send(sb.toString());
		}
	}

	private String stripQuotes(String s) {
		if (s.length() > 1 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"') {
			s = s.substring(1, s.length() - 1);
		}
		return s;
	}

	private void sendInvalidValueMessage(String value) throws RemoteException {
		ctxSet(DefaultMessageFactory.CTXKEY_VAL + "Value", value);
		sendHelper().sendMessage(user, getInvalidValueKey());
	}

	protected void sendSetVoidValueMessage() throws RemoteException {
		sendHelper().sendMessage(user, getVoidSetKey());
	}

	protected void sendSetValueMessage(String value) throws RemoteException, CommandException {
		ctxSet(DefaultMessageFactory.CTXKEY_VAL + "Value", value);
		sendHelper().sendMessage(user, getSuccesfulSetKey());
	}

	protected void permissionCheck() throws PermissionException, RemoteException {
	}

	private String getDefault(String key) {
		return (String) user.getProperty(key).defaultValue();
	}

	protected String showSettings() throws RemoteException, PropertyStoreException {
		StringBuilder sb = new StringBuilder();
		sb.append(getString(getHeaderKey(), user.getProperties()));
		Iterator i = setUpKeys().iterator();
		while (i.hasNext()) {
			String key = (String) i.next();
			String val = getValue(key);
			if (val == null) {
				val = "";
			}
			ctxSet(DefaultMessageFactory.CTXKEY_VAL + "Key", key);
			ctxSet(DefaultMessageFactory.CTXKEY_VAL + "Val", val);
			sb.append(getString("set.showItem", user.getProperties()));
		}
		sb.append(getString(getFooterKey(), user.getProperties()));
		return sb.toString();
	}

	protected abstract String setValue(String key, String value) throws RemoteException, PropertyStoreException, PersistenceException;

	protected abstract Set<String> getValidValues(String key) throws RemoteException;

	protected abstract String getValue(String key) throws RemoteException, PropertyStoreException;

	/**
	 * Provides set of settable properties.
	 * @return set of properties or null if there is no restricting set
	 */
	protected abstract Set<String> settable();

	/**
	 * Currently set up keys. Default implementation returns settable.
	 * @return set of properties/keys that are set up (default settable)
	 * @throws RemoteException
	 * @throws PropertyStoreException
	 */
	protected Set<String> setUpKeys() throws RemoteException, PropertyStoreException {
		return settable();
	}

	protected String getPropertyNotFoundKey() {
		return "set.propNotFound";
	}

	protected String getInvalidValueKey() {
		return "set.invalidValue";
	}

	protected String getSuccesfulSetKey() {
		return "set.propSet";
	}

	protected String getVoidSetKey() {
		return "set.propVoidSet";
	}

	protected String getCurrentValueKey() {
		return "set.currentValue";
	}

	protected String getValidValuesKey() {
		return "set.validValues";
	}

	protected String getHeaderKey() {
		return "set.head";
	}

	protected String getFooterKey() {
		return "set.tail";
	}
}
